package tk.mybatis.web.plugin;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import tk.mybatis.web.utils.PageInfo;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Map;
import java.util.Properties;

/**
 * @author: chenhs
 * @date: Created in 17:09 2020/4/4
 **/
@Intercepts(@Signature(
        type = StatementHandler.class,
        method = "prepare",
        args = {Connection.class, Integer.class}
))
public class AllenPagePlugin implements Interceptor {

    private static final String PAGE = ".*ByPage$";

    /**
     * * 分页实现
     * * 1.拿到原始sql
     * * 2.增加分页
     * * 3.执行jdbc去查询总数
     *
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        //类似spring context getBean("userBean");
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");

        //获取mapper接口中的方法名称 selectByPage
        String mapperMethodName = mappedStatement.getId();
        //处理所有ByPage结尾的方法
        if (mapperMethodName.matches(PAGE)) {
            BoundSql boundSql = statementHandler.getBoundSql();
            String sql = boundSql.getSql();
            System.out.println("原始sql：" + sql);

            String countSql = "select count(0) from (" + sql + ") a";
            System.out.println("查询总数sql: "+ countSql);

            //执行jdbc操作
            Connection connection = (Connection) invocation.getArgs()[0];
            PreparedStatement countStatement = connection.prepareStatement(countSql);
            ParameterHandler parameterHandler = (ParameterHandler) metaObject.getValue("delegate.parameterHandler");
            parameterHandler.setParameters(countStatement);

            ResultSet rs = countStatement.executeQuery();
            //分页参数
            Object paramObj = boundSql.getParameterObject();
            Map<String, Object> paramMap = (Map<String, Object>) paramObj;
            PageInfo pageInfo = (PageInfo) paramMap.get("page");
            if (rs.next()) {
                pageInfo.setTotalNumber(rs.getInt(1));
            }
            rs.close();
            countStatement.close();

            //改造原始sql 实现分页
            String pageSql = generatePageSql(sql, pageInfo);
            System.out.println("分页sql:　"+ pageSql);

            metaObject.setValue("delegate.boundSql.sql", pageSql);
        }
        //把执行流程交回给mybatis
        return invocation.proceed();
    }

    /**
     * 把自定义的插件加入到mybatis中去执行
     *
     * @param target
     * @return
     */
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    /**
     * 设置属性
     *
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {

    }


    public String generatePageSql(String sql, PageInfo pageInfo){
        StringBuilder sb = new StringBuilder();
        sb.append(sql);
        sb.append(" limit "+ pageInfo.getStartIndex() + ", "+ pageInfo.getTotalSelect());
        return sb.toString();
    }
}
